package network;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;

public class UdpEchoServer {

    // 需要先定义一个socket对象
    // 通过网络通信,必须使用socket对象
    private DatagramSocket socket = null;

    // 绑定一个端口, 不一定能成功 如果某个端口号已经被别的进程占用了,此时这里的绑定操作就会出错
    // 同一个主机 一个端口 , 只能被一个进程绑定
    public UdpEchoServer(int port) throws SocketException {
        // 构造socket的同时,指定要关联/绑定的端口
        socket = new DatagramSocket(port);

    }

    public void start() throws IOException {
        System.out.println(" 服务器启动 ");
        // 读取请求并解析
        // 根据请求计算响应 (此处省略这个步骤,直接返回请求)
        // 把响应结果写回到客户端
        while(true) {
            // 1.读取请求并解析
            // 构造空饭盒
            DatagramPacket requestPacket =
                    new DatagramPacket(new byte[4096],4096);
            // 食堂大妈给饭盒装饭
            socket.receive(requestPacket); // 如果客户端没有发送数据,此时receive就会阻塞
            // 为了方便处理请求,把数据包转成string 不构造成String也可以
            String request = new String(requestPacket.getData(),0,
                    requestPacket.getLength());
            // getLength是得到数组的实际长度,而不是数组的长度(4096)
            System.out.println(request);
            // 如果客户端发来的数据是"老板来一份蛋炒粉",此时这个数据就会以二进制
            // 的形式躺在requestPacket中的字节数组中把这个数组拿出来,重新构造
            // string,这个string就是"老板来一份蛋炒粉"
            // 2.把响应结果写回到客户端
            String response = process(request);
            // 3.根据请求计算响应 (此处省略这个步骤,直接返回请求)
            // 根据response字符串,计算一个DatagramPacket
            // 和请求的packet不同,构造响应的时候,需要指定包发给谁
            DatagramPacket responsePacket = new DatagramPacket(
                    response.getBytes(),
                    response.getBytes().length,
                    // 客户端的ip和端口
                    requestPacket.getSocketAddress());
            socket.send(responsePacket);
            // System.out.println(responsePacket.getSocketAddress());
            System.out.printf("[%s %d] req %s resp %s\n" ,
                    requestPacket.getAddress().toString(),
                    requestPacket.getPort(),
                    request,
                    response);

        }
    }

    // 这个方法是根据请求计算响应
    // 由于我们写的是回显程序,请求是什么,响应是什么,如果后续写个别的服务器,不再回显了
    // 而是有具体的业务,就可以修改process方法,根据需求计算响应
    public String process(String request) {
        return request;
    }

    public static void main(String[] args) throws IOException {
        UdpEchoServer udpEchoServer = new UdpEchoServer(9090);
        udpEchoServer.start();
    }

}
